/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.activiti.explorer.ui.management.identity;

import com.vaadin.ui.*;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.themes.Reindeer;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.explorer.ExplorerApp;
import org.activiti.explorer.I18nManager;
import org.activiti.explorer.Messages;
import org.activiti.explorer.data.LazyLoadingContainer;
import org.activiti.explorer.data.LazyLoadingQuery;
import org.activiti.explorer.ui.Images;
import org.activiti.explorer.ui.custom.ConfirmationDialogPopupWindow;
import org.activiti.explorer.ui.custom.DetailPanel;
import org.activiti.explorer.ui.custom.SelectUsersPopupWindow;
import org.activiti.explorer.ui.event.ConfirmationEvent;
import org.activiti.explorer.ui.event.ConfirmationEventListener;
import org.activiti.explorer.ui.event.SubmitEvent;
import org.activiti.explorer.ui.event.SubmitEventListener;
import org.activiti.explorer.ui.mainlayout.ExplorerLayout;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;


/**
 * @author Joram Barrez
 */
public class GroupDetailPanel extends DetailPanel implements MemberShipChangeListener {

    private static final long serialVersionUID = 1L;

    protected transient IdentityService identityService;
    protected I18nManager i18nManager;

    protected GroupPage groupPage;
    protected Group group;
    protected VerticalLayout panelLayout;
    protected boolean editingDetails;
    protected HorizontalLayout detailLayout;
    protected GridLayout detailsGrid;
    protected TextField nameTextField;
    protected ComboBox typeCombobox;
    protected HorizontalLayout membersLayout;
    protected Table membersTable;
    protected Label noMembersTable;

    public GroupDetailPanel(GroupPage groupPage, String groupId) {
        this.groupPage = groupPage;
        this.identityService = ProcessEngines.getDefaultProcessEngine().getIdentityService();
        this.group = identityService.createGroupQuery().groupId(groupId).singleResult();
        this.i18nManager = ExplorerApp.get().getI18nManager();

        init();
    }

    protected void init() {
        setSizeFull();
        addStyleName(Reindeer.PANEL_LIGHT);

        initPageTitle();
        initGroupDetails();
        initMembers();

        initActions();
    }

    protected void initActions() {
        Button createGroupButton = new Button(i18nManager.getMessage(Messages.GROUP_CREATE));
        createGroupButton.setIcon(Images.GROUP_16);
        createGroupButton.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                NewGroupPopupWindow popup = new NewGroupPopupWindow();
                ExplorerApp.get().getViewManager().showPopupWindow(popup);
            }
        });
        groupPage.getToolBar().removeAllButtons();
        groupPage.getToolBar().addButton(createGroupButton);
    }

    protected void initPageTitle() {
        HorizontalLayout layout = new HorizontalLayout();
        layout.setWidth(100, UNITS_PERCENTAGE);
        layout.addStyleName(ExplorerLayout.STYLE_TITLE_BLOCK);
        layout.setSpacing(true);
        layout.setMargin(false, false, true, false);
        addDetailComponent(layout);

        Embedded groupImage = new Embedded(null, Images.GROUP_50);
        layout.addComponent(groupImage);

        Label groupName = new Label(getGroupName(group));
        groupName.setSizeUndefined();
        groupName.addStyleName(Reindeer.LABEL_H2);
        layout.addComponent(groupName);
        layout.setComponentAlignment(groupName, Alignment.MIDDLE_LEFT);
        layout.setExpandRatio(groupName, 1.0f);
    }

    protected String getGroupName(Group theGroup) {
        if (theGroup.getName() == null) {
            return theGroup.getId();
        }
        return group.getName();
    }

    protected void initGroupDetails() {
        Label groupDetailsHeader = new Label(i18nManager.getMessage(Messages.GROUP_HEADER_DETAILS));
        groupDetailsHeader.addStyleName(ExplorerLayout.STYLE_H3);
        groupDetailsHeader.addStyleName(ExplorerLayout.STYLE_DETAIL_BLOCK);

        addDetailComponent(groupDetailsHeader);

        detailLayout = new HorizontalLayout();
        detailLayout.setSpacing(true);
        detailLayout.setMargin(true, false, true, false);
        addDetailComponent(detailLayout);

        populateGroupDetails();
    }

    protected void populateGroupDetails() {
        initGroupProperties();
        initGroupActions();
    }

    protected void initGroupProperties() {
        detailsGrid = new GridLayout(2, 3);
        detailsGrid.setSpacing(true);
        detailLayout.setMargin(true, true, true, false);
        detailLayout.addComponent(detailsGrid);

        // id
        Label idLabel = new Label(i18nManager.getMessage(Messages.GROUP_ID) + ": ");
        idLabel.addStyleName(ExplorerLayout.STYLE_LABEL_BOLD);
        detailsGrid.addComponent(idLabel);
        Label idValueLabel = new Label(group.getId());
        detailsGrid.addComponent(idValueLabel);

        // name
        Label nameLabel = new Label(i18nManager.getMessage(Messages.GROUP_NAME) + ": ");
        nameLabel.addStyleName(ExplorerLayout.STYLE_LABEL_BOLD);
        detailsGrid.addComponent(nameLabel);
        if (!editingDetails) {
            Label nameValueLabel = new Label(group.getName());
            detailsGrid.addComponent(nameValueLabel);
        } else {
            nameTextField = new TextField(null, group.getName());
            detailsGrid.addComponent(nameTextField);
        }

        // Type
        Label typeLabel = new Label(i18nManager.getMessage(Messages.GROUP_TYPE) + ": ");
        typeLabel.addStyleName(ExplorerLayout.STYLE_LABEL_BOLD);
        detailsGrid.addComponent(typeLabel);
        if (!editingDetails) {
            Label typeValueLabel = new Label(group.getType());
            detailsGrid.addComponent(typeValueLabel);
        } else {
            typeCombobox = new ComboBox(null, Arrays.asList("assignment", "security-role"));
            typeCombobox.setNullSelectionAllowed(false);
            typeCombobox.setInvalidAllowed(false);
            typeCombobox.select(group.getType());
            detailsGrid.addComponent(typeCombobox);
        }
    }

    protected void initGroupActions() {
        VerticalLayout actionsLayout = new VerticalLayout();
        actionsLayout.setSpacing(true);
        actionsLayout.setMargin(false, false, false, true);
        detailLayout.addComponent(actionsLayout);

        if (editingDetails) {
            initSaveButton(actionsLayout);
        } else {
            initEditButton(actionsLayout);
            initDeleteButton(actionsLayout);
        }
    }

    protected void initEditButton(VerticalLayout actionsLayout) {
        Button editButton = new Button(i18nManager.getMessage(Messages.USER_EDIT));
        editButton.addStyleName(Reindeer.BUTTON_SMALL);
        actionsLayout.addComponent(editButton);

        editButton.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                editingDetails = true;
                detailLayout.removeAllComponents();
                populateGroupDetails();
            }
        });
    }

    protected void initSaveButton(VerticalLayout actionsLayout) {
        Button saveButton = new Button(i18nManager.getMessage(Messages.USER_SAVE));
        saveButton.addStyleName(Reindeer.BUTTON_SMALL);
        actionsLayout.addComponent(saveButton);

        saveButton.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                String originalName = group.getName();

                // Update data
                if (nameTextField.getValue() != null) {
                    group.setName(nameTextField.getValue().toString());
                    group.setType(typeCombobox.getValue().toString());
                }
                identityService.saveGroup(group);

                // Update UI
                editingDetails = false;
                detailLayout.removeAllComponents();
                populateGroupDetails();

                // Refresh task list (only if name was changed)
                if ((originalName != null && !originalName.equals(group.getName()))
                        || (originalName == null && group.getName() != null)) {
                    groupPage.notifyGroupChanged(group.getId());
                }
            }
        });
    }

    protected void initDeleteButton(VerticalLayout actionsLayout) {
        Button deleteButton = new Button(i18nManager.getMessage(Messages.GROUP_DELETE));
        deleteButton.addStyleName(Reindeer.BUTTON_SMALL);
        actionsLayout.addComponent(deleteButton);

        deleteButton.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                ConfirmationDialogPopupWindow confirmPopup =
                        new ConfirmationDialogPopupWindow(i18nManager.getMessage(Messages.GROUP_CONFIRM_DELETE, group.getId()));
                confirmPopup.addListener(new ConfirmationEventListener() {
                    protected void rejected(ConfirmationEvent event) {
                    }

                    protected void confirmed(ConfirmationEvent event) {
                        // Delete group from database
                        identityService.deleteGroup(group.getId());

                        // Update ui
                        groupPage.refreshSelectNext();
                    }
                });

                ExplorerApp.get().getViewManager().showPopupWindow(confirmPopup);
            }
        });
    }

    protected void initMembers() {
        HorizontalLayout membersHeader = new HorizontalLayout();
        membersHeader.setSpacing(true);
        membersHeader.setWidth(100, UNITS_PERCENTAGE);
        membersHeader.addStyleName(ExplorerLayout.STYLE_DETAIL_BLOCK);
        addDetailComponent(membersHeader);

        initMembersTitle(membersHeader);
        initAddMembersButton(membersHeader);

        membersLayout = new HorizontalLayout();
        membersLayout.setWidth(100, UNITS_PERCENTAGE);
        addDetailComponent(membersLayout);
        initMembersTable();
    }

    protected void initMembersTitle(HorizontalLayout membersHeader) {
        Label usersHeader = new Label(i18nManager.getMessage(Messages.GROUP_HEADER_USERS));
        usersHeader.addStyleName(ExplorerLayout.STYLE_H3);
        membersHeader.addComponent(usersHeader);
    }

    protected void initAddMembersButton(HorizontalLayout membersHeader) {
        Button addButton = new Button();
        addButton.addStyleName(ExplorerLayout.STYLE_ADD);
        membersHeader.addComponent(addButton);
        membersHeader.setComponentAlignment(addButton, Alignment.MIDDLE_RIGHT);

        addButton.addListener(new ClickListener() {
            public void buttonClick(ClickEvent event) {
                final SelectUsersPopupWindow selectUsersPopup = new SelectUsersPopupWindow(
                        i18nManager.getMessage(Messages.GROUP_SELECT_MEMBERS, group.getId()),
                        true, false, getCurrentMembers());
                ExplorerApp.get().getViewManager().showPopupWindow(selectUsersPopup);

                // Listen to submit events (that contain the selected users)
                selectUsersPopup.addListener(new SubmitEventListener() {
                    protected void submitted(SubmitEvent event) {
                        Collection<String> userIds = selectUsersPopup.getSelectedUserIds();
                        if (!userIds.isEmpty()) {
                            for (String userId : userIds) {
                                identityService.createMembership(userId, group.getId());
                            }
                            notifyMembershipChanged();
                        }
                    }

                    protected void cancelled(SubmitEvent event) {
                    }
                });
            }
        });
    }

    // Hacky - must be put in custom service
    protected List<String> getCurrentMembers() {
        List<User> users = identityService.createUserQuery().memberOfGroup(group.getId()).list();
        List<String> userIds = new ArrayList<String>();
        for (User user : users) {
            userIds.add(user.getId());
        }
        return userIds;
    }

    protected void initMembersTable() {
        LazyLoadingQuery query = new GroupMembersQuery(group.getId(), this);
        if (query.size() > 0) {
            membersTable = new Table();
            membersTable.setWidth(100, UNITS_PERCENTAGE);
            membersTable.setHeight(400, UNITS_PIXELS);

            membersTable.setEditable(false);
            membersTable.setSelectable(false);
            membersTable.setSortDisabled(false);

            LazyLoadingContainer container = new LazyLoadingContainer(query, 30);
            membersTable.setContainerDataSource(container);

            membersTable.addContainerProperty("id", Button.class, null);
            membersTable.addContainerProperty("firstName", String.class, null);
            membersTable.addContainerProperty("lastName", String.class, null);
            membersTable.addContainerProperty("email", String.class, null);
            membersTable.addContainerProperty("actions", Component.class, null);

            membersLayout.addComponent(membersTable);
        } else {
            noMembersTable = new Label(i18nManager.getMessage(Messages.GROUP_NO_MEMBERS));
            membersLayout.addComponent(noMembersTable);
        }
    }

    public void notifyMembershipChanged() {
        membersLayout.removeAllComponents();
        initMembersTable();
    }

}
